<?php

namespace services\infusion;

use common\models\patient\InfusionPrintLog;
use common\models\patient\Tags;
use services\base\DrugService;
use Yii;
use common\models\patient\UserAttr;
use common\models\member\Member;
use common\models\patient\DrugRecord;
use common\helpers\CommonHelper;
use common\models\base\Drug;
use common\models\base\DrugConfig;
use common\models\clinic\Clinic;
use common\models\patient\DrugSurplus;
use common\models\patient\InfusionQueue;
use common\models\patient\InfusionQueueDrug;
use common\models\patient\User;
use common\components\Service;

/**
 * Class PatientService
 * @package services\infusion
 */
class TreatmentService extends Service
{
    /**
     * 患者列表
     *
     * @param array $params
     * @param int $page
     * @param int $pageSize
     * @return array
     */
    public function getPatientList(array $params, int $page, int $pageSize): array
    {
        $query = User::find()
            ->alias('a')
            ->select([
                'a.id', 'a.name', 'a.age', 'a.gender', 'a.clinic_id', 'a.patient_card_id', 'a.last_infusion_time', 'a.mobile',
                'b.type', 'c.last_operate_time', 'c.in_hospital_status'
            ])
            ->leftJoin(UserAttr::tableName() . ' c', 'a.id = c.patient_user_id')
            ->leftJoin(DrugRecord::tableName() . ' b', 'a.id = b.patient_user_id and b.created_at = c.last_operate_time')
            ->where([
                'a.project_id' => Yii::$app->params['project_id'],
                'a.status' => [User::STATUS_INVALID, User::STATUS_ENABLE]
            ])
//            ->orderBy(['c.last_operate_time' => SORT_DESC])
            ->groupBy(['a.id']);
        if (isset($params['keywords']) && $params['keywords']) {
            $query->andWhere([
                'or',
                ['a.mobile' => trim($params['keywords'])],
                ['a.patient_card_id' => trim($params['keywords'])],
                ['a.name' => trim($params['keywords'])],
            ]);
        }
        // 日期筛选由上次输液时间修改为上次操作（新增，停止医嘱，治疗）时间
        if (isset($params['start_time']) && $params['start_time']) {
            $query->andWhere(['>=', 'c.last_operate_time', strtotime($params['start_time'])]);
        }
        if (isset($params['end_time']) && $params['end_time']) {
            $query->andWhere(['<=', 'c.last_operate_time', strtotime($params['end_time']) + 86399]);
        }
        if (isset($params['clinic_id']) && $params['clinic_id']) {
            $query->andWhere(['a.clinic_id' => $params['clinic_id']]);
        }
        // 操作类型
        if (isset($params['record_type']) && $params['record_type']) {
            $query->andWhere(['b.type' => $params['record_type']]);
        }
        // 默认上次操作时间倒序
        $orderBy['c.last_operate_time'] = SORT_DESC;
        $orderBy['a.id'] = SORT_DESC;
        $list = $this->getListPageRes($query, $page, $pageSize, $orderBy);
        if ($list['list']) {
            foreach ($list['list'] as &$val) {
                $val['last_infusion_time'] = $val['last_infusion_time'] ? date('Y-m-d H:i:s', $val['last_infusion_time']) : '';
                $val['last_operate_time'] = $val['last_operate_time'] ? date('Y-m-d H:i:s', $val['last_operate_time']) : '';
                $val['gender'] = User::$genders[$val['gender']];
                $clinic = Clinic::findOne($val['clinic_id']);
                $val['clinic_name'] = $clinic ? $clinic->name : '';
                $val['type_name'] = $val['type'] ? DrugRecord::$type[$val['type']] : '';
                $val['tags_name_arr'] = self::getPatientTags($val['id']);
            }
        }
        return $list;
    }

    /**
     * 治疗-剩余数
     *
     * @param int $patientId
     * @param string $type
     * @return array|\yii\db\ActiveRecord[]
     */
    public function patientDrugSurplus(int $patientId, string $type = '')
    {
        $list = $this->getPatientDrugSurplus($patientId, $type);

        foreach ($list as &$ds) {
            $ds['drug_volume'] = round($ds['drug_volume'], 2);
            $haveQueue = InfusionQueueDrug::find()
                ->alias('a')
                ->leftJoin(InfusionQueue::tableName() . ' b', 'a.queue_id = b.id')
                ->where(['a.drug_surplus_id' => $ds['id'], 'b.status' => [InfusionQueue::STATUS_WAIT, InfusionQueue::STATUS_CALLING]])
                ->andWhere(['between', 'b.created_at', strtotime(date('Y-m-d')), strtotime(date('Y-m-d')) + 86399])
                ->asArray()
                ->one();

            // 可退数量如果存在排队中的则要减去排队可能消耗的药品
            $ds['can_refund'] = $ds['surplus_num'];
            if ($haveQueue) {
                $ds['can_refund'] = $ds['surplus_num'] - $haveQueue['use_num'];
            }

            $ds['drug_type_name'] = DrugConfig::$drugTypes[$ds['drug_type']];
//            $ds['water_type_name'] = $ds['water_type'] ? DrugConfig::$waterTypes[$ds['water_type']] : '';
            $ds['all_name'] = DrugService::getDrugContent((int)$ds['drug_id'], $ds['drug_name'], $ds['drug_unit'], $ds['drug_type'], $ds['drug_volume'], $ds['water_type'], $ds['water_volume']);
        }
        return $list;
    }

    /**
     * 获取患者剩余数
     * @param int $patientId
     * @param string $type
     * @return array
     */
    public function getPatientDrugSurplus(int $patientId, string $type = ''): array
    {
        $query = DrugSurplus::find()
            ->alias('a')
            ->select([
                'a.*', 'b.drug_id', 'b.drug_type', 'b.drug_volume',
                'b.water_type', 'b.water_volume', 'c.drug_name', 'c.drug_unit',
            ])
            ->leftJoin(User::tableName() . ' pa', 'a.patient_user_id = pa.id')
            ->leftJoin(DrugConfig::tableName() . ' b', 'a.drug_config_id = b.id')
            ->leftJoin(Drug::tableName() . ' c', 'b.drug_id = c.id')
            ->where(['a.patient_user_id' => $patientId])
            ->groupBy(['b.id']);
        if ($type == 'not_select') {
            $query->andWhere(['a.status' => DrugSurplus::STATUS_ENABLE]);
        }
        return $query->asArray()->all();
    }

    /**
     * 治疗-更新药品剩余数
     */
    public function updatePatientDrugSurplus(array $params, string $type = 'add')
    {
        $haveDrug = DrugSurplus::find()->where([
            'id' => $params['drug_surplus_id'],
            'status' => DrugSurplus::STATUS_ENABLE,
            'patient_user_id' => $params['patient_user_id']
        ])->one();
        if (!$haveDrug) {
            return CommonHelper::api(422, '患者不存在该药品');
        }

        $transaction = Yii::$app->db->beginTransaction();
        try {
            if ($type == 'add') {// 新增药品
                DrugSurplus::updateAll(
                    ['surplus_num' => $haveDrug->surplus_num + $params['operate_num'], 'updated_at' => time()],
                    ['id' => $params['drug_surplus_id']]
                );
                // 患者药品记录
                $createdAt = $this->createDrugRecord($params, DrugRecord::TYPE_ADD, $haveDrug->drug_config_id);
                // 更新患者的上次操作时间
                $this->updatePatientLastOperateTime($params['patient_user_id'], $createdAt);
            } elseif ($type == 'refund') {// 退费
                $haveQueue = InfusionQueueDrug::find()
                    ->alias('a')
                    ->leftJoin(InfusionQueue::tableName() . ' b', 'a.queue_id = b.id')
                    ->where(['a.drug_surplus_id' => $params['drug_surplus_id'], 'b.status' => [InfusionQueue::STATUS_WAIT, InfusionQueue::STATUS_CALLING]])
                    ->andWhere(['between', 'b.created_at', strtotime(date('Y-m-d')), strtotime(date('Y-m-d')) + 86399])
                    ->asArray()
                    ->one();

                // 退费数量不能大于患者已存在药品数量【如果存在排队中的则要去除排队可能消耗的药品】
                if ($haveQueue) {
                    $maxRefund = $haveDrug->surplus_num - $haveQueue['use_num'];
                } else {
                    $maxRefund = $haveDrug->surplus_num;
                }
                if ($maxRefund < $params['operate_num']) {
                    return CommonHelper::api(422, '药品剩余数量不足');
                }
                // 更新患者药品数量
                DrugSurplus::updateAll(
                    ['surplus_num' => $haveDrug->surplus_num - $params['operate_num'], 'updated_at' => time()],
                    ['id' => $params['drug_surplus_id']]
                );
                // 患者药品记录
                $createdAt = $this->createDrugRecord($params, DrugRecord::TYPE_REFUND, $haveDrug->drug_config_id);
                // 更新患者的上次操作时间
                $this->updatePatientLastOperateTime($params['patient_user_id'], $createdAt);
            }
            $transaction->commit();
            return true;
        } catch (\Exception $exception) {
            $transaction->rollBack();
            throw new \Exception($exception->getMessage(), 500);
        }
    }

    /**
     * 删除患者的药品
     */
    public function deletePatientDrugSurplus(array $params)
    {
        $haveDrug = DrugSurplus::find()->where([
            'id' => $params['drug_surplus_id'],
            'status' => DrugSurplus::STATUS_ENABLE,
            'patient_user_id' => $params['patient_user_id']
        ])->one();
        if (!$haveDrug) {
            return CommonHelper::api(422, '患者不存在该药品或已删除');
        }
        if ($haveDrug->surplus_num > 0) {
            return CommonHelper::api(422, '患者药品还有剩余，不能删除');
        }

        return DrugSurplus::updateAll(
            ['status' => DrugSurplus::STATUS_DELETE, 'updated_at' => time()],
            ['id' => $params['drug_surplus_id']]
        );
    }

    /**
     * 患者输液记录
     *
     * @param array $params
     * @param int $page
     * @param int $pageSize
     * @return array|int[]
     */
    public function drugRecordList(array $params, int $page, int $pageSize)
    {
        $query = DrugRecord::find()
            ->alias('a')
            ->select([
                'a.*', 'b.drug_id', 'b.drug_type',
                'b.drug_volume', 'b.water_type',
                'b.water_volume', 'c.id surplus_id',
                'd.drug_name', 'd.drug_unit', 'm.realname operate_name'
            ])
            ->leftJoin(DrugConfig::tableName() . ' b', 'a.drug_config_id = b.id')
            ->leftJoin(DrugSurplus::tableName() . ' c', 'a.drug_config_id = c.drug_config_id and a.patient_user_id = c.patient_user_id')
            ->leftJoin(Drug::tableName() . ' d', 'b.drug_id = d.id')
            ->leftJoin(Member::tableName() . ' m', 'a.operate_id = m.id')
            ->where(['a.patient_user_id' => $params['patient_user_id']])
            ->orderBy(['a.created_at' => SORT_DESC]);
        if (isset($params['start_time']) && $params['start_time']) {
            $query->andWhere(['>=', 'a.created_at', strtotime($params['start_time'])]);
        }
        if (isset($params['end_time']) && $params['end_time']) {
            $query->andWhere(['<=', 'a.created_at', strtotime($params['end_time']) + 86399]);
        }
        if (isset($params['drug_type']) && $params['drug_type']) {
            $query->andWhere(['b.drug_type' => $params['drug_type']]);
        }
        if (isset($params['surplus_id']) && $params['surplus_id']) {
            $query->andWhere(['c.id' => $params['surplus_id']]);
        }
        if (isset($params['type']) && $params['type']) {
            $query->andWhere(['a.type' => $params['type']]);
        }
        $list = $this->getListPageRes($query, $page, $pageSize);
        if ($list['list']) {
            foreach ($list['list'] as &$val) {
                $val['drug_volume'] = round($val['drug_volume'], 2);
                $val['created_at'] = date('Y-m-d H:i:s', $val['created_at']);
                $val['drug_type_name'] = DrugConfig::$drugTypes[$val['drug_type']];
//                $val['water_type_name'] = $val['water_type'] ? DrugConfig::$waterTypes[$val['water_type']] : '';
                $val['type_name'] = DrugRecord::$type[$val['type']];
                $val['all_name'] = DrugService::getDrugContent($val['drug_id'], $val['drug_name'], $val['drug_unit'], $val['drug_type'], $val['drug_volume'], $val['water_type'], $val['water_volume']);
            }
        }
        return $list;
    }

    /**
     * 治疗-配置患者项目
     *
     * @param $params
     * @return array|bool|mixed
     * @throws \Exception
     */
    public function createPatientDrugSurplus($params)
    {
        $drugList = $params['config_list'];
        $transaction = Yii::$app->db->beginTransaction();
        try {
            $nowTime = time();
            $addList = [];
            foreach ($drugList as $val) {
                $val['drug_id'] = isset($val['drug_id']) && $val['drug_id'] ? $val['drug_id'] : 0;
                $val['drug_volume'] = isset($val['drug_volume']) && $val['drug_volume'] ? $val['drug_volume'] : 0;
                $val['water_type'] = isset($val['water_type']) && $val['water_type'] ? $val['water_type'] : 0;
                $val['water_volume'] = isset($val['water_volume']) && $val['water_volume'] ? $val['water_volume'] : 0;
                if ($val['water_volume']) {
                    if (is_int($val['water_volume']) == false) {
                        return CommonHelper::api(422, '水容量不能为小数');
                    }
                }
                if ($val['drug_id'] || $val['drug_volume'] || $val['water_volume'] || $val['water_type']) {
                    if (($val['drug_id'] && !$val['drug_volume']) || (!$val['drug_id'] && $val['drug_volume'])) {
                        return CommonHelper::api(422, '配置项目不能为空');
                    }
                    if (($val['water_volume'] && !$val['water_type']) || ($val['water_volume'] && !$val['water_type'])) {
                        return CommonHelper::api(422, '配置项目不能为空');
                    }
                } else {
                    return CommonHelper::api(422, '配置项目不能为空');
                }

                // 添加药品配置表 如果存在药品，则不添加
                if ($val['drug_type'] == DrugConfig::DRUG_TYPE_JD) {
                    /*if (!$val['water_volume']) {
                        return CommonHelper::api(422, '请输入液体剂量');
                    }*/
                    $drugConfigIs = DrugConfig::findOne([
                        'drug_id' => $val['drug_id'],
                        'drug_type' => $val['drug_type'],
                        'drug_volume' => $val['drug_volume'],
                        'water_type' => $val['water_type'],
                        'water_volume' => $val['water_volume']
                    ]);
                } else {
                    $drugConfigIs = DrugConfig::findOne([
                        'drug_id' => $val['drug_id'],
                        'drug_type' => $val['drug_type'],
                        'drug_volume' => $val['drug_volume'],
                    ]);
                }
                if ($drugConfigIs) {
                    $drugConfigId = $drugConfigIs->id;
                } else {
                    $drugConfigIs = new DrugConfig();
                    $drugConfigIs->drug_id = $val['drug_id'];
                    $drugConfigIs->drug_type = $val['drug_type'];
                    $drugConfigIs->drug_volume = $val['drug_volume'];
                    $drugConfigIs->water_type = $val['water_type'] ?? 0;
                    $drugConfigIs->water_volume = $val['water_volume'] ?? 0;
                    $drugConfigIs->saveAndCheckResult();
                    $drugConfigId = $drugConfigIs->id;
                }

                // 更新患者药品剩余
                if ($drugSurplusIs = DrugSurplus::findOne([
                    'patient_user_id' => $params['patient_user_id'], 'drug_config_id' => $drugConfigId
                ])) {
                    $surplusNum = $drugSurplusIs->surplus_num + $val['operate_num'];
                } else {
                    $drugSurplusIs = new DrugSurplus();
                    $surplusNum = $val['operate_num'];
                }
                $drugSurplusIs->patient_user_id = $params['patient_user_id'];
                $drugSurplusIs->drug_config_id = $drugConfigId;
                $drugSurplusIs->surplus_num = $surplusNum;
                $drugSurplusIs->status = DrugSurplus::STATUS_ENABLE;
                $drugSurplusIs->saveAndCheckResult();

                // 患者药品新增记录
                $addRecord['patient_user_id'] = $params['patient_user_id'];
                $addRecord['drug_config_id'] = $drugConfigId;
                $addRecord['type'] = DrugRecord::TYPE_ADD;
                $addRecord['operate_num'] = $val['operate_num'];
                $addRecord['remark'] = $val['remark'] ?? '';
                $addRecord['operate_id'] = Yii::$app->user->identity->member_id;
                $addRecord['created_at'] = $nowTime;
                $addRecord['updated_at'] = $nowTime;
                $addList[] = $addRecord;
            }
            if ($addList) {
                $finAddList = [];
                // 判断是否有重复的药品，存在则合并
                foreach ($addList as $al) {
                    if (isset($finAddList[$al['drug_config_id']]) && $finAddList[$al['drug_config_id']]) {
                        $finAddList[$al['drug_config_id']]['operate_num'] += $al['operate_num'];
                    } else {
                        $finAddList[$al['drug_config_id']] = $al;
                    }
                }
                Yii::$app->db->createCommand()
                    ->batchInsert(DrugRecord::tableName(),
                        ['patient_user_id', 'drug_config_id', 'type', 'operate_num', 'remark', 'operate_id', 'created_at', 'updated_at'],
                        $finAddList)
                    ->execute();

            }
            // 更新患者的上次操作时间
            $this->updatePatientLastOperateTime($params['patient_user_id'], $nowTime);

            $transaction->commit();
            return true;
        } catch (\Exception $exception) {
            $transaction->rollBack();
            throw new \Exception($exception->getMessage(), 500);
        }
    }

    public function createDrugRecord($params, $type, $drugConfigId)
    {
        $model = new DrugRecord();
        $model->patient_user_id = $params['patient_user_id'];
        $model->drug_config_id = $drugConfigId;
        $model->type = $type;
        $model->operate_num = $params['operate_num'];
        $model->remark = $params['remark'] ?? '';
        $model->operate_id = Yii::$app->user->identity->member_id;
        if ($model->saveAndCheckResult()) {
            return $model->created_at;
        } else {
            return time();
        }
    }

    /**
     * @Notes: 药品下拉列表
     * @Interface getDrugList
     * @return array[]
     * @author: chenyuebin
     * @Time: 2022/4/25 0025   13:48
     */
    public function getDrugList()
    {
        $drugList = Drug::find()
            ->select(['id', 'drug_name', 'drug_unit', 'drug_type'])
            ->where([
                'status' => Drug::STATUS_ENABLE
            ])
            ->orderBy(['sort' => SORT_ASC, 'id' => SORT_DESC])
            ->asArray()
            ->all();
        $drugListJd = $drugListJz = [];
        foreach ($drugList as $value) {
            if ($value['drug_type'] == Drug::DRUG_TYPE_JD) {
                array_push($drugListJd, $value);
                continue;
            }
            array_push($drugListJz, $value);
        }

        return ['drug_list_jd' => $drugListJd, 'drug_list_jz' => $drugListJz];
    }

    /**
     * 更新打印次数
     */
    public function updatePrintTimes($params)
    {
        /**
         * @var InfusionQueue $model
         */
        $model = InfusionQueue::find()->where(
            [
                'and',
                [
                    'id' => $params['queue_id'],
                    'status' => [InfusionQueue::STATUS_WAIT, InfusionQueue::STATUS_CALLING]
                ],
                ['between', 'created_at', strtotime(date('Y-m-d')), strtotime(date('Y-m-d')) + 86399]
            ]
        )->one();
        if (!$model) {
            return CommonHelper::api(422, '今天暂无此待叫号或叫号中的患者');
        }

        // 1.更新打印次数 py\xs
        if ($params['print_type'] == 'py') {
            $model->print_py_num += 1;
            $type = InfusionPrintLog::TYPE_PY;
        } else {
            $model->print_xs_num += 1;
            $type = InfusionPrintLog::TYPE_XS;
        }
        $model->saveAndCheckResult();

        // 2.添加打印日志
        // 队列药品信息
        $queueDrugList = QueueDrugService::getQueueDrugList($model->id);
        $drugConfigIds = array_column($queueDrugList, 'drug_config_id');
        PrintLogService::create($model, $type, $drugConfigIds);

        return $model;
    }

    /**
     * 更新患者信息扩展表by_patient_user_attr的上次操作时间
     */
    public function updatePatientLastOperateTime(int $patientId, int $operateTime = null)
    {
        $model = UserAttr::findOne(['patient_user_id' => $patientId]);
        if (!$model) {
            $model = new UserAttr();
        }
        $model->patient_user_id = $patientId;
        $model->last_operate_time = $operateTime ?: time();
        return $model->saveAndCheckResult();
    }

    /**
     * 更新患者信息扩展表上次操作时间【输液大厅对患者的药品的最后一次操作时间】
     */
    public function updateAllOperateTime()
    {
        $list = DrugRecord::find()
            ->select(['patient_user_id'])
            ->where(['>=', 'patient_user_id', 0])
            ->groupBy(['patient_user_id'])
            ->asArray()
            ->all();
        foreach ($list as $val) {
            $patientDrugRecord = DrugRecord::find()
                ->select(['created_at', 'patient_user_id'])
                ->where(['patient_user_id' => $val['patient_user_id']])
                ->orderBy(['created_at' => SORT_DESC])
                ->asArray()
                ->one();
            $this->updatePatientLastOperateTime($patientDrugRecord['patient_user_id'], $patientDrugRecord['created_at']);
        }
        return $list;
    }

    /**
     * 获取药品配置的最后一次备注
     * @param int $drugConfigId
     * @param int $patientUserId
     * @return string
     */
    public static function getLastDrugRemark(int $drugConfigId, int $patientUserId): string
    {
        $record = DrugRecord::find()
            ->select(['id', 'remark'])
            ->where([
                'patient_user_id' => $patientUserId,
                'drug_config_id' => $drugConfigId,
                'type' => [DrugRecord::TYPE_ADD, DrugRecord::TYPE_REFUND]
            ])
            ->orderBy(['id' => SORT_DESC])
            ->asArray()
            ->one();
        return $record ? $record['remark'] : '';
    }

    public static function getPatientTags(int $patientUserId)
    {
        return Tags::find()
            ->alias('pt')
            ->select(['mt.tags_name'])
            ->leftJoin(\common\models\marketing\Tags::tableName() . ' mt', 'pt.tags_id = mt.id')
            ->where(['pt.status' => Tags::STATUS_ENABLE, 'pt.patient_user_id' => $patientUserId])
            ->orderBy(['mt.sort' => SORT_ASC])
            ->asArray()
            ->column();
    }
}